package com.wmjsoft.validator

import com.wmjsoft.validator.anno.NotBlank
import com.wmjsoft.validator.anno.NotEmpty
import com.wmjsoft.validator.anno.NotNull
import com.wmjsoft.validator.anno.Valid
import com.wmjsoft.view.token.TestValidator
import io.vertx.core.MultiMap
import net.cloudopt.next.web.Resource
import net.cloudopt.next.web.Validator
import java.lang.reflect.Field
import java.util.concurrent.ConcurrentHashMap
import java.util.logging.Logger
import kotlin.collections.ArrayList

abstract class BaseValidator : Validator {

    val log = Logger.getLogger(BaseValidator::class.simpleName)


    var params = ConcurrentHashMap<String, Any>()

    var result = HashMap<String,Any>()

    var resultFlag = false

    lateinit var  resource:Resource

    abstract fun valid()

    fun getValue(fieldName: String): Any? {
        return this.params[fieldName]
    }

    override suspend fun error(resource: Resource) {
        resource.renderJson(result)
    }

    override suspend fun validate(resource: Resource): Boolean {
        this.resource = resource
        initParams(resource)
        val fields = this::class.java.declaredFields
        startValidator(fields,this.params)
        valid()

        if(this.resultFlag) {
            return false
        }

        return true
    }

    private fun startValidator(fields: Array<Field>,params: ConcurrentHashMap<String, Any>){
        fields.forEach {
            val annotations = ArrayList<Annotation>(it.annotations.toList())
            when (val annotation = this.subValidator(it, annotations)) {
                is NotNull -> notNull(it,annotation.msg,annotation.code,params)
                is NotBlank -> notBlank(it,annotation.msg,annotation.code,params)
                is NotEmpty -> notEmpty(it,annotation.msg,annotation.code,params)
            }
        }
    }

    private fun subValidator(field: Field,annotations:ArrayList<Annotation>): Annotation? {
        var annotation:Annotation? = null
        annotations.forEach {
            if(it is Valid){
              // todo
            }else{
                annotation = it
            }
        }
        return annotation
    }

    /**
     * 将前台传进来的参数统一管理,然后进行认证
     */
    private fun initParams(resource: Resource) {
        //url后的参数
        val params = resource.request.params()
        addParams(params)
        //body application/json的传参类型
        val bodyAsJson = resource.context.bodyAsJson
        addParams(bodyAsJson?.map)

        //form data
        val formData = resource.request.formAttributes()
        addParams(formData)
    }

    private fun addParams(params: Map<String, Any>?) {
        params?.forEach { (t,u) ->
            if(null !== u) {
                this.params[t] = u
            }
        }
    }

//    private fun addSubParams(params: Map<String, Any>?): ConcurrentHashMap<String, Any> {
//        val result:ConcurrentHashMap<String,Any> = ConcurrentHashMap()
//        params?.forEach { (t,u) ->
//            if(null !== u) {
//                result[t] = u
//            }
//        }
//        return result
//    }

    private fun addParams(params: MultiMap?) {
        params?.forEach { (t,u) ->
            if(null !== u) {
                this.params[t] = u
            }
        }
    }

    private fun renderJson(field: Field, msg:String, code:Int) {
        this.result[field.name] = Result(code,msg)
        this.resultFlag = true
    }


    fun renderJson(field: String,msg: String) {
        this.result[field] = "errorMsg:$msg"
        this.resultFlag = true
    }


    private fun notNull(field: Field,msg: String,code: Int,params: ConcurrentHashMap<String, Any>): Boolean {
        if(params[field.name] != null) {
            return true
        }else{
            renderJson(field,msg,code)
        }

        return false
    }

    private fun notEmpty(field: Field,msg: String,code: Int,params: ConcurrentHashMap<String, Any>) : Boolean {
        if(this.notNull(field,msg,code,params)){
            val result = params[field.name]
            if(result is Map<*, *>) {
                if(result.size > 0) {
                    return true
                }else{
                    renderJson(field,msg,code)
                }
            } else if(result is List<*>){
                if(result.size > 0) {
                    return true
                }else{
                    renderJson(field,msg,code)
                }
            }
        }
        return false
    }

    private fun notBlank(field: Field,msg: String,code: Int,params: ConcurrentHashMap<String, Any>): Boolean {
        if(this.notNull(field,msg,code,params)){
            val res = params[field.name]
            if(res is String) {
                if("" != res){
                    return true
                }else{
                    renderJson(field,msg,code)
                }
            }
        }
        return false
     }
}

data class Result (var errorCode:Int,var errorMsg:String)
